package net.homelinux.chaoswg.io.renga.core.registries;

import java.util.HashMap;
import java.util.Map;

import net.homelinux.chaoswg.io.higherorderfunctions.BinaryFunction;
import net.homelinux.chaoswg.io.higherorderfunctions.BinaryPredicate;
import net.homelinux.chaoswg.io.higherorderfunctions.ConstantFunction;
import net.homelinux.chaoswg.io.higherorderfunctions.NAryFunction;
import net.homelinux.chaoswg.io.higherorderfunctions.QuadtaryFunction;
import net.homelinux.chaoswg.io.higherorderfunctions.QuintaryFunction;
import net.homelinux.chaoswg.io.higherorderfunctions.TernaryFunction;
import net.homelinux.chaoswg.io.higherorderfunctions.UnaryFunction;
import net.homelinux.chaoswg.io.renga.core.helper.functions.IsOfType;

public class FunctionRegistry {
    private final BinaryPredicate<Class, Object> isOfType = new IsOfType ();
    
    private static Map<String, NAryFunction> _functionMap;
    private static Map<String, Integer> _functionArgumentNumberMap;
    
    private static FunctionRegistry _this = null;
    
    private FunctionRegistry () {
        _functionMap = new HashMap<String, NAryFunction> ();
        _functionArgumentNumberMap = new HashMap<String, Integer> ();
    }
    
    public static FunctionRegistry getCentralRegistry () {
        if (_this == null) {
            _this = new FunctionRegistry ();
        }
        
        return _this;
    }
    
    public NAryFunction getFunctionByName (final String functionName) {
        final NAryFunction _tmp = _functionMap.get(functionName);
        
        if (_tmp == null) {
            throw new MethodNotDefinedFunction (); 
        } else {
            return _tmp;
        }
    }
    
    public void setFunctionByName (final String functionName, final NAryFunction function) {
        _functionMap.put(functionName, function);
        
        if (isOfType.apply(ConstantFunction.class, function)) {
            _functionArgumentNumberMap.put(functionName, 0);
        } else if (isOfType.apply(UnaryFunction.class, function)) {
            _functionArgumentNumberMap.put(functionName, 1);
        } else if (isOfType.apply(BinaryFunction.class, function)) {
            _functionArgumentNumberMap.put(functionName, 2);
        } else if (isOfType.apply(TernaryFunction.class, function)) {
            _functionArgumentNumberMap.put(functionName, 3);
        } else if (isOfType.apply(QuadtaryFunction.class, function)) {
            _functionArgumentNumberMap.put(functionName, 4);
        } else if (isOfType.apply(QuintaryFunction.class, function)) {
            _functionArgumentNumberMap.put(functionName, 5);
        }
    }
    
    public Integer getNumberOfArgumentsForFunctionByName (final String functionName) {
        return _functionArgumentNumberMap.get(functionName);
    }
}
